﻿using System;
using System.IO;
using System.Web;
using HgCo.WindowsLive.SkyDrive;
using API.WindowsLive.SkyDrive.Events;

namespace API.WindowsLive.SkyDrive.BusinessLogic
{
    partial class SkyDriveLogic
    {
        public void checkFilesInLocalDirectory()
        {
            checkFilesInLocalDirectory(webSyncRootDirectory);
        }

        private void checkFilesInLocalDirectory(WebFolderInfo webFolder)
        {
            if (!localDirectoryExists(webFolder))
            {
                flagAllWebFilesAsNotExists(webFolder);
                return;
            }

            WebFileInfo[] webFiles = getWebFiles(webFolder);
            foreach (WebFileInfo webFileInfo in webFiles)
            {
                WebFileInfo webFile = skyDrive.GetWebFile(webFileInfo);
                if (!checkIfDownloadFile(webFile, true))
                {
                    markWebFileAsNotExists(webFile);
                }
            }

            WebFolderInfo[] subFolders = getSubDirectories(webFolder);
            foreach (WebFolderInfo webFolderInfo in subFolders)
            {
                WebFolderInfo webFolderIteration = skyDrive.GetWebFolder(webFolderInfo);
                checkFilesInLocalDirectory(webFolderIteration);
            }
        }

        public void Download()
        {
            processDownloadDirectory(webSyncRootDirectory);
        }

        private void processDownloadDirectory(WebFolderInfo webFolder)
        {
            if (!localDirectoryExists(webFolder))
            {
                createLocalDirectory(webFolder);
            }

            DirectoryInfo currentLocalDirectory = getLocalDirectory(webFolder);

            WebFileInfo[] webFiles = skyDrive.ListSubWebFolderFiles(webFolder);
            foreach (WebFileInfo webFileInfo in webFiles)
            {
                WebFileInfo webFile = skyDrive.GetWebFile(webFileInfo);
                if (!checkIfDownloadFile(webFile, true))
                {
                    downloadToLocal(webFile, currentLocalDirectory);
                }
            }

            WebFolderInfo[] webFolders = skyDrive.ListSubWebFolders(webFolder);
            foreach (WebFolderInfo webFolderIteration in webFolders)
            {
                WebFolderInfo currentWebFolder = skyDrive.GetWebFolder(webFolderIteration);
                processDownloadDirectory(currentWebFolder);
            }
        }

        private void downloadToLocal(WebFileInfo webFile, DirectoryInfo directory)
        {
            try
            {
                if (SplitLargeFiles.isSplitFile(webFile.FullName))
                {
                    if (SplitLargeFiles.isFirstSplitFile(webFile.FullName))
                    {
                        FileChanged(this, new FileChangedEventArgs(webFile.PathUrl, SplitLargeFiles.getFileName(webFile.FullName), 0, (long)webFile.SizeMax, FileChangedEventArgs.EventTypeEnum.download));

                        if (!checkThatAllPartsExist(webFile))
                            throw new Exception(String.Format("Web file {0} is missing some part files and will not be stiched back correctly", SplitLargeFiles.getFileName(webFile.Name)));

                        String[] getAllPartsFileNames = SplitLargeFiles.getAllFileNames(webFile.FullName);
                        long totalSize = getTotalSizeOfPartFiles( webFile);
                        long downloadSoFar = 0;

                        using (FileStream fileStream = new FileStream(getLocalFile(webFile).FullName, FileMode.OpenOrCreate))
                        {
                            foreach (String partFileName in getAllPartsFileNames)
                            {
                                WebFileInfo partWebFile = this.getWebFile(partFileName, getParentWebDirectory(webFile));
                                    //getWebDirectoryFromPathURL(webFile.PathUrl));

                                using (Stream stream = skyDrive.DownloadWebFile(partWebFile))
                                {
                                    byte[] buffer = new byte[64 * 1024];
                                    int count = 0;
                                    long startTicks = DateTime.Now.Ticks;

                                    while ((count = stream.Read(buffer, 0, buffer.Length)) > 0)
                                    {
                                        fileStream.Write(buffer, 0, count);
                                        downloadSoFar += (long)count;

                                        if ((DateTime.Now.Ticks - startTicks) > waitTicksBeforeRaiseProgressEvent)
                                        {
                                            FileChanged(this, new FileChangedEventArgs(webFile.PathUrl, SplitLargeFiles.getFileName(webFile.FullName), downloadSoFar, totalSize, FileChangedEventArgs.EventTypeEnum.downloadProgress));
                                            startTicks = DateTime.Now.Ticks;
                                        }
                                    }

                                }
                            }
                        }

                        FileChanged(this, new FileChangedEventArgs(webFile.PathUrl, SplitLargeFiles.getFileName(webFile.FullName), 0, (long)webFile.SizeMax, FileChangedEventArgs.EventTypeEnum.downloadCompleted));
                    }
                    else
                    {
                        if(!checkThatAllPartsExist(webFile))
                            throw new Exception(String.Format("Web file {0} is missing some part files and will not be stiched back correctly", SplitLargeFiles.getFileName(webFile.Name)));
                    }
                }
                else
                {
                    FileChanged(this, new FileChangedEventArgs(webFile.PathUrl, webFile.FullName, 0, (long)webFile.SizeMax, FileChangedEventArgs.EventTypeEnum.download));
                    WebFileInfo webFile2 = skyDrive.GetWebFile(webFile);
                    using (Stream stream = skyDrive.DownloadWebFile(webFile2))
                    {
                        using (FileStream fileStream = new FileStream(getLocalFile(webFile).FullName, FileMode.OpenOrCreate))
                        {
                            byte[] buffer = new byte[64 * 1024];
                            int count = 0;
                            long downloadSoFar = 0;
                            long startTicks = DateTime.Now.Ticks;

                            while ((count = stream.Read(buffer, 0, buffer.Length)) > 0)
                            {
                                fileStream.Write(buffer, 0, count);
                                downloadSoFar += (long)count;

                                if ((DateTime.Now.Ticks - startTicks) > waitTicksBeforeRaiseProgressEvent)
                                {
                                    FileChanged(this, new FileChangedEventArgs(webFile.PathUrl, webFile.FullName, downloadSoFar, (long)webFile.SizeMax, FileChangedEventArgs.EventTypeEnum.downloadProgress));
                                    startTicks = DateTime.Now.Ticks; 
                                }
                            }
                        }
                    }

                    FileChanged(this, new FileChangedEventArgs(webFile.PathUrl, webFile.FullName, 0, (long)webFile.SizeMax, FileChangedEventArgs.EventTypeEnum.downloadCompleted));
                }
            }
            catch (Exception ex)
            {
                ExceptionRaised(this, new ExceptionEventArgs(ex, ExceptionEventArgs.ExceptionLocationEnum.download));
            }

        }

        private void flagAllWebFilesAsNotExists(WebFolderInfo mainWebFolderInfo)
        {
            WebFileInfo[] webFiles = skyDrive.ListSubWebFolderFiles(mainWebFolderInfo); //mainWebFolderInfo.GetFiles();
            foreach (WebFileInfo webFileInfo in webFiles)
            {
                WebFileInfo webFile = skyDrive.GetWebFile(webFileInfo);
                if(!(SplitLargeFiles.isSplitFile(webFile.FullName) && !SplitLargeFiles.isFirstSplitFile(webFile.FullName)))
                    markWebFileAsNotExists(webFile);
            }

            WebFolderInfo[] webFolders = skyDrive.ListSubWebFolders(mainWebFolderInfo); // mainWebFolderInfo.GetSubFolders()
            foreach (WebFolderInfo webFolderInfo in webFolders)
            {
                WebFolderInfo webFolder = skyDrive.GetWebFolder(webFolderInfo);
                flagAllWebFilesAsNotExists(webFolder);
            }
        }

        private void markWebFileAsNotExists(WebFileInfo file)
        {
            filesToDownload.Add(file);

            String fileFullName = "";
            String fileName = "";

            if (SplitLargeFiles.isSplitFile(file.FullName))
            {
                
                fileFullName = SplitLargeFiles.getFileName(HttpUtility.UrlDecode(file.PathUrl));
                fileName = SplitLargeFiles.getFileName(file.FullName);
            }
            else
            {
                fileFullName = file.FullName;
                fileName = file.Name;
            }
            FileChanged(this, new FileChangedEventArgs(fileFullName, fileName, 0, 0, FileChangedEventArgs.EventTypeEnum.addForDownload));
        }

        private Boolean fileContainedInDownloads(WebFileInfo webFile)
        {
            foreach (WebFileInfo webFileInfo in filesToDownload)
            {
                if (webFileInfo.PathUrl.Equals(webFile.PathUrl))
                {
                    return true;
                }
            }
            return false;
        }

        public void deleteLocalFilesIfNotInWeb()
        {
            deleteLocalFilesIfNotInWeb(localSyncRootDirectory);
        }

        private void deleteLocalFilesIfNotInWeb(DirectoryInfo directoryInfo)
        {
            if (!webDirectoryExists(directoryInfo))
            {
                FileChanged(this, new FileChangedEventArgs(directoryInfo.FullName, directoryInfo.Name, 0, 0, FileChangedEventArgs.EventTypeEnum.deleteLocalFolder));
                Directory.Delete(directoryInfo.FullName, true);
                return;
            }

            FileInfo[] files = directoryInfo.GetFiles();

            foreach (FileInfo fileInfo in files)
            {
                if (!checkIfUploadFile(fileInfo))
                {
                    FileChanged(this, new FileChangedEventArgs(fileInfo.FullName, fileInfo.Name, 0, fileInfo.Length, FileChangedEventArgs.EventTypeEnum.deleteLocalFile));
                    fileInfo.Delete();
                }
            }

            DirectoryInfo[] directories = directoryInfo.GetDirectories();

            foreach (DirectoryInfo directoryInfoIteration in directories)
                deleteLocalFilesIfNotInWeb(directoryInfoIteration);

        }

        private long getTotalSizeOfPartFiles(WebFileInfo webFile)
        {
            WebFolderInfo webFolderInfo = getParentWebDirectory(webFile);
            String[] getAllPartsFileNames = SplitLargeFiles.getAllFileNames(webFile.FullName);
            long totalSize = (long)webFile.SizeMax * (getAllPartsFileNames.Length - 1) + (long)getWebFile(getAllPartsFileNames[getAllPartsFileNames.Length - 1], webFolderInfo).SizeMax;
            return totalSize;
        }

        private Boolean checkThatAllPartsExist(WebFileInfo webFile)
        {
            String[] allFileNames = SplitLargeFiles.getAllFileNames(webFile.FullName);

            WebFolderInfo webFolder = getParentWebDirectory(webFile);

            foreach (String fileNameIteration in allFileNames)
            {
                if (!checkIfFileInWebDirectory(fileNameIteration, webFolder))
                    return false;
            }

            return true;
        }

    }
}
